// 定义包路径
package com.lxx.jmb2c.service.impl;

// 导入相关类

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lxx.jmb2c.dto.*;
import com.lxx.jmb2c.dto.*;
import com.lxx.jmb2c.entity.Member;
import com.lxx.jmb2c.exceptions.BusinessException;
import com.lxx.jmb2c.handlers.BaseContextHandler;
import com.lxx.jmb2c.mapper.MemberMapper;
import com.lxx.jmb2c.service.MemberService;
import com.lxx.jmb2c.utils.JwtUtil;
import com.lxx.jmb2c.vo.MemberInfoVO;
import com.lxx.jmb2c.vo.MemberPageVO;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 会员服务实现类
 * 实现会员相关的业务逻辑，包括登录、获取用户信息、更新密码等功能
 *
 * @author wuyunbin
 * @since 2025-07-02
 */
// 启用日志功能
@Slf4j
// 标记为服务类
@Service
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements MemberService {

    // 注入HttpServletRequest，用于获取请求中的信息（如token）
    @Resource
    private HttpServletRequest request;

    // 注入JWT工具类，用于处理token
    @Resource
    private JwtUtil jwtUtil;

    // 注入微信小程序服务，用于处理微信登录等相关操作
    @Resource
    private WxMaService wxMaService;

    @Resource
    private BCryptPasswordEncoder passwordEncoder;


    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 用户登录实现
     * 支持账号密码登录，验证用户身份并生成JWT令牌
     *
     * @param memberLoginDTO 登录信息数据传输对象
     * @return 生成的JWT令牌
     * @throws BusinessException 当账号不存在或密码错误时抛出
     */
    @Override
    public String login(MemberLoginDTO memberLoginDTO) {
        // 初始化会员对象
        Member member = null;

        // 账号密码登录
        if (memberLoginDTO.getMobile() != null) {
            // 创建查询条件
            LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
            // 根据手机号查询用户
            wrapper.eq(Member::getMobile, memberLoginDTO.getMobile());
            // 获取用户信息
            member = this.getOne(wrapper);

            // 检查用户是否存在
            if (member == null) {
                log.info("账号不存在");
                throw new BusinessException("账号不存在或密码错误");
            }

            // 验证密码是否正确
            log.info("密码：{}", passwordEncoder.encode(memberLoginDTO.getPassword()));
            if (!passwordEncoder.matches(memberLoginDTO.getPassword(), member.getPassword())) {
                log.info("密码错误");
                throw new BusinessException("账号不存在或密码错误");
            }
        } else {
            // 微信小程序登录流程
            String openId = null;
            // 获取openId
            WxMaJscode2SessionResult session = null;
            try {
                // 调用微信API获取session信息
                session = wxMaService.getUserService().getSessionInfo(memberLoginDTO.getCode());
                // 从session中提取openId
                openId = session.getOpenid();
                // 验证openId是否成功获取
                if (openId == null) {
                    log.info("获取openId失败");
                    throw new BusinessException("获取openId失败");
                }
            } catch (WxErrorException e) {
                // 捕获微信API调用异常
                throw new BusinessException("获取openId失败");
            }

            // 创建查询条件
            LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
            // 根据openId查询用户
            wrapper.eq(Member::getOpenId, openId);
            // 获取用户信息
            member = this.getOne(wrapper);

            // 检查用户是否存在
            if (member == null) {
                // 创建新用户
                member = new Member();
                // 设置openId
                member.setOpenId(openId);
                // 保存用户信息
                this.save(member);
            }
        }

        // 签发token
        HashMap<String, Object> map = new HashMap<>();
        // 将用户ID存入token
        map.put("id", member.getUserId());
        // 生成JWT令牌
        return jwtUtil.generateToken(map);
    }

    /**
     * 获取当前登录用户信息
     * 从请求头中获取token，解析出用户ID，然后查询用户信息
     *
     * @return 当前登录用户的信息
     */
    @Override
    public MemberInfoVO info() {
        Long id = BaseContextHandler.get();
        log.info("id:{}", id);
        // 根据用户ID查询用户信息
        Member member = this.getById(id);
        //member->memberInfoVO
        MemberInfoVO memberInfoVO = new MemberInfoVO();
        //属性对拷-属性名一致的情况下属性可以对拷
        BeanUtils.copyProperties(member, memberInfoVO);
        //隐藏部分手机号
        String mobile = member.getMobile();
        // 135-5921-0925
        mobile = mobile.substring(0, 3) + "****" + mobile.substring(7);
        memberInfoVO.setMobile(mobile);
        return memberInfoVO;
    }

    /**
     * 更新用户密码
     * 根据用户ID更新密码信息
     *
     * @param memberUpdatePasswordDTO 密码更新信息数据传输对象
     */
    @Override
    public void updatePassword(MemberUpdatePasswordDTO memberUpdatePasswordDTO) {
        // 从请求头获取token
        String token = request.getHeader("Authorization");
        log.info("token:{}", token);

        if (token == null || token.equals("")) {
            throw new BusinessException("token为空");
        }

        // 解析token，获取用户ID
        Claims claims = jwtUtil.parseToken(token);
        Integer id = claims.get("id", Integer.class);
        // 创建Member对象
        Member member = this.getById(id);

        if (member == null) {
            throw new BusinessException("用户不存在");
        }

        // 验证新密码
        if (!passwordEncoder.matches(memberUpdatePasswordDTO.getOldPassword(), member.getPassword())) {
            log.info("旧密码错误");
            throw new BusinessException("旧密码错误");
        }
        // 设置新密码
        member.setPassword(passwordEncoder.encode(memberUpdatePasswordDTO.getNewPassword()));
        // 更新用户信息
        this.updateById(member);
    }

    @Override
    public Member register(MemberRegisterDTO memberRegisterDTO) {
        //验证码是否正确
        if (!StringUtils.hasText(memberRegisterDTO.getCode())) {
            throw new BusinessException("验证码为空");
        }

        if (!redisTemplate.hasKey("code")) {
            throw new BusinessException("验证码已过期");
        }

        String code = redisTemplate.opsForValue().get("code");

        if (code == null) {
            throw new BusinessException("验证码已过期");
        }

        if (!code.equals(memberRegisterDTO.getCode())) {
            throw new BusinessException("验证码错误");
        }
        //检查手机号是否已注册&检查邮箱是否已注册
        //
        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.hasText(memberRegisterDTO.getMobile()), Member::getMobile, memberRegisterDTO.getMobile());
        wrapper.eq(StringUtils.hasText(memberRegisterDTO.getEmail()), Member::getEmail, memberRegisterDTO.getEmail());
        Member member = this.getOne(wrapper);

        if (member != null) {
            if (StringUtils.hasText(memberRegisterDTO.getMobile())) {
                throw new BusinessException("手机号已注册");
            }
            if (StringUtils.hasText(memberRegisterDTO.getEmail())) {
                throw new BusinessException("邮箱已注册");
            }
        }

        //检查密码是否合法
        if (!StringUtils.hasText(memberRegisterDTO.getPassword())) {
            throw new BusinessException("密码不能为空");
        }
        //存储进数据库
        //解决member是null，直接调用方法会抛空指针异常的问题
        member = new Member();
        member.setEmail(memberRegisterDTO.getEmail());
        member.setMobile(memberRegisterDTO.getMobile());
        //密码需要从明文加密成密文然后再入库
        member.setPassword(passwordEncoder.encode(memberRegisterDTO.getPassword()));
        this.save(member);
        //删除验证码
        redisTemplate.delete("code");
        log.info("member:{}", member);
        return member;
    }

    @Override
    public void bindPhoneOrEmailOrOpenId(MemberBindAccountDTO memberBindAccountDTO) {

    }


    @Override
    public IPage<MemberPageVO> getPage(MemberPageQueryDTO memberPageQueryDTO) {
        /*
        mybatis-plus分页支持的泛型是Member->Page<Member>
        但是这里需要的是Page<MemberPageVO>，所以需要 Page<Member> 转成 Page<MemberPageVO>
         */
        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.hasText(memberPageQueryDTO.getMobile()), Member::getMobile, memberPageQueryDTO.getMobile());
        wrapper.eq(StringUtils.hasText(memberPageQueryDTO.getEmail()), Member::getEmail, memberPageQueryDTO.getEmail());
        wrapper.eq(StringUtils.hasText(memberPageQueryDTO.getTrueName()), Member::getTrueName, memberPageQueryDTO.getTrueName());
        wrapper.eq(memberPageQueryDTO.getStatus() != null, Member::getStatus, memberPageQueryDTO.getStatus());

        Page<Member> page = this.page(new Page<>(memberPageQueryDTO.getCurrent(), memberPageQueryDTO.getPageSize()), wrapper);
        //分析page的结构得到一个结论，转换类型只需要考虑records
        List<Member> records = page.getRecords();
        //创建一个page对象，用于返回
        Page<MemberPageVO> pageVO = new Page<>();
        //数据对拷 -> 会有一个问题，pageVO里面的records会被page中的records覆盖
        BeanUtils.copyProperties(page,pageVO);
        //恢复pageVO中的records
        List<MemberPageVO> voList=new ArrayList<>();
        //遍历records，将Member对象转换成MemberPageVO对象
        for (Member member : records) {
            MemberPageVO memberPageVO = new MemberPageVO();
            BeanUtils.copyProperties(member,memberPageVO);
            //需要一个List<MemberPageVO>对象接收改造好的memberPageVO对象,没有则需要创建
           voList.add(memberPageVO);
        }
        pageVO.setRecords(voList);
        log.info("page:{}", page);
        return pageVO;
    }

    /**
     * 启用或禁用会员
     * 根据会员当前状态进行切换：启用 -> 禁用，禁用 -> 启用
     *
     * @param id 会员ID
     */
    @Override
    public void enable(Long id) {
        // 1. 根据ID获取会员当前信息
        Member member = this.getById(id);
        if (member == null) {
            throw new BusinessException("会员不存在");
        }
        
        // 2. 切换会员状态
        member.setStatus(!member.getStatus());
        
        // 3. 更新会员信息
        this.updateById(member);
        
        log.info("会员ID: {}, 状态已更新为: {}", id, member.getStatus() ? "启用" : "禁用");
    }

    @Override
    public void resetPassword(Long id) {

    }
}
